In [1]:
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np

import torch
import torch.optim as optim
from torchvision import transforms, models
In [2]:
vgg = models.vgg19(weights='VGG19_Weights.DEFAULT').features
for param in vgg.parameters():
    param.requires_grad_(False)
vgg
Downloading: "https://download.pytorch.org/models/vgg19-dcbb9e9d.pth" to /root/.cache/torch/hub/checkpoints/vgg19-dcbb9e9d.pth
100%|██████████| 548M/548M [00:11<00:00, 49.9MB/s]
Out[2]:
Sequential(
  (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (1): ReLU(inplace=True)
  (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (3): ReLU(inplace=True)
  (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (6): ReLU(inplace=True)
  (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (8): ReLU(inplace=True)
  (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (11): ReLU(inplace=True)
  (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (13): ReLU(inplace=True)
  (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (15): ReLU(inplace=True)
  (16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (17): ReLU(inplace=True)
  (18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (20): ReLU(inplace=True)
  (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (22): ReLU(inplace=True)
  (23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (24): ReLU(inplace=True)
  (25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (26): ReLU(inplace=True)
  (27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (29): ReLU(inplace=True)
  (30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (31): ReLU(inplace=True)
  (32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (33): ReLU(inplace=True)
  (34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (35): ReLU(inplace=True)
  (36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
In [31]:
def load_image(img_path, max_size=400, shape=None):

    image = Image.open(img_path).convert('RGB')

    # decrease the size of the image
    if max(image.size) > max_size:
        size = max_size
    else:
        size = max(image.size)

    if shape is not None:
        size = shape

    in_transform = transforms.Compose([
                        transforms.Resize(size),
                        transforms.ToTensor(),
                        transforms.Normalize((0.485, 0.456, 0.406),
                                             (0.229, 0.224, 0.225))])
    image = in_transform(image)[:3,:,:].unsqueeze(0)

    return image

  # load in content and style image
content = load_image('content.png')
# Resizing style and content
style = load_image('634.jpg', shape=content.shape[-2:])

# converting it from a Tensor image to a NumPy image for display
def im_convert(tensor):
    """ Display a tensor as an image. """

    image = tensor.to("cpu").clone().detach()
    image = image.numpy().squeeze()
    image = image.transpose(1,2,0)
    image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))
    image = image.clip(0, 1)

    return image

# display the images
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
ax1.imshow(im_convert(content))
ax2.imshow(im_convert(style))
Out[31]:
<matplotlib.image.AxesImage at 0x7f244d0d0520>
In [32]:
def get_features(image, model, layers=None):
    if layers is None:
        layers = {'0': 'conv1_1',
                 '2':  'conv2_1',
                 '5': 'conv3_1',
                 '8': 'conv4_1',
                 '10': 'conv4_2',
                 '12': 'conv5_1'}

    features = {}
    x = image
    for name, layer in model._modules.items():
        x = layer(x)
        if name in layers:
            features[layers[name]] = x

    return features
In [33]:
def gram_matrix(tensor):


    gram = None
    b, d, h, w = tensor.size()
    tensor = tensor.view(d, h*w)
    gram = torch.mm(tensor, tensor.t())
    return gram

#content and style features
content_features = get_features(content, vgg)
style_features = get_features(style, vgg)

# gram matrices for each layer of our style representation
style_grams = {layer: gram_matrix(style_features[layer]) for layer in style_features}
target = content.clone().requires_grad_(True)
In [34]:
style_weights = {'conv1_1': 20,
'conv2_1': 16,
'conv3_1': 12,
'conv4_1': 8,
'conv5_1': 4}

content_weight = 1 
style_weight = 1e6 
In [35]:
def deep_dream(image, model, steps, step_size):
    image = image.clone().detach().requires_grad_(True)
    for step in range(steps):
        model.zero_grad()
        out = model(image)
        loss = out.mean()
        loss.backward()
        avg_grads = image.grad.data.mean(dim=(0, 2, 3), keepdim=True)
        image.data += avg_grads * step_size
    return image
In [38]:
show_every = 10
# iteration hyperparameters
optimizer = optim.Adam([target], lr=0.003)
steps = 100  # decide how many iterations

for ii in range(1, steps+1):

    ## content loss
    target_features = get_features(target, vgg)
    content_loss = torch.mean((target_features["conv4_2"] - content_features["conv4_2"]) ** 2)

    # style loss
    style_loss = 0
    # iterate through each style layer and add to the style loss
    for layer in style_weights:
        target_feature = target_features[layer]
        _, d, h, w = target_feature.shape
        target_gram = gram_matrix(target_feature)
        style_gram = style_grams[layer]
        layer_style_loss = style_weights[layer] * torch.mean((target_gram - style_gram) ** 2)

        # add to the style loss
        style_loss += layer_style_loss / (d * h * w)

    total_loss = content_weight * content_loss + style_weight * style_loss

    # Update your target image
    optimizer.zero_grad()
    total_loss.backward()
    optimizer.step()

    if ii % 100 == 0:  # Adjust the frequency of deep dreaming
        target = deep_dream(target, vgg, 20, 0.1)

    if ii % show_every == 0:
        print('Total loss:', total_loss.item())
        plt.imshow(im_convert(target))
        plt.show()

# display content and final, target image
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(20, 10))
ax1.imshow(im_convert(content))
ax2.imshow(im_convert(target))
Total loss: 40393158656.0
Total loss: 36977537024.0
Total loss: 33845512192.0
Total loss: 30982524928.0
Total loss: 28372215808.0
Total loss: 25997838336.0
Total loss: 23843923968.0
Total loss: 21895743488.0
Total loss: 20141535232.0
Total loss: 18568712192.0
Out[38]:
<matplotlib.image.AxesImage at 0x7f244d87f250>
In [ ]: